frontend/pages/e/[uuid].tsx (view raw)
1import {useState, useReducer, useEffect} from 'react';
2import Box from '@material-ui/core/Box';
3import {makeStyles} from '@material-ui/core/styles';
4import {useTranslation} from 'react-i18next';
5import {initializeApollo} from '../../lib/apolloClient';
6import useToastStore from '../../stores/useToastStore';
7import useEventStore from '../../stores/useEventStore';
8import Layout from '../../layouts/Default';
9import AddToMyEventDialog from '../../containers/AddToMyEventDialog';
10import TravelColumns from '../../containers/TravelColumns';
11import NewTravelDialog from '../../containers/NewTravelDialog';
12import VehicleChoiceDialog from '../../containers/VehicleChoiceDialog';
13import WelcomeDialog from '../../containers/WelcomeDialog';
14import EventBar from '../../containers/EventBar';
15import Loading from '../../containers/Loading';
16import OnBoardingTour from '../../containers/OnBoardingTour';
17import {
18 useUpdateEventMutation,
19 Event as EventType,
20 useEventByUuidQuery,
21 EventByUuidDocument,
22 EditEventInput,
23} from '../../generated/graphql';
24import ErrorPage from '../_error';
25import AddTravel from '../../containers/TravelColumns/AddTravel';
26import useProfile from '../../hooks/useProfile';
27import Fab from '../../containers/Fab';
28
29const POLL_INTERVAL = 10000;
30
31interface Props {
32 event: EventType;
33 eventUUID: string;
34}
35
36const EventPage = props => {
37 const {t} = useTranslation();
38 const {event} = props;
39 if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
40 return <Event {...props} />;
41};
42
43const Event = (props: Props) => {
44 const {eventUUID} = props;
45 const classes = useStyles();
46 const {t} = useTranslation();
47 const {user} = useProfile();
48 const addToast = useToastStore(s => s.addToast);
49 const setEvent = useEventStore(s => s.setEvent);
50 const eventUpdate = useEventStore(s => s.event);
51 const setIsEditing = useEventStore(s => s.setIsEditing);
52 const [updateEvent] = useUpdateEventMutation();
53 const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
54 const [openNewTravel, toggleNewTravel] = useReducer(i => !i, false);
55 const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
56 const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
57 pollInterval: POLL_INTERVAL,
58 variables: {uuid: eventUUID},
59 });
60
61 useEffect(() => {
62 if (event) setEvent(event as EventType);
63 }, [event]);
64
65 const onSave = async e => {
66 try {
67 const {uuid, ...data} = eventUpdate;
68 const {id, __typename, travels, users, waitingList, ...input} = data;
69 await updateEvent({
70 variables: {uuid, eventUpdate: input as EditEventInput},
71 refetchQueries: ['eventByUUID'],
72 });
73 setIsEditing(false);
74 } catch (error) {
75 console.error(error);
76 addToast(t('event.errors.cant_update'));
77 }
78 };
79
80 const onShare = async () => {
81 if (!event) return null;
82 // If navigator share capability
83 if (!!navigator.share)
84 return await navigator.share({
85 title: `Caroster ${event.name}`,
86 url: `${window.location.href}`,
87 });
88 // Else copy URL in clipboard
89 else if (!!navigator.clipboard) {
90 await navigator.clipboard.writeText(window.location.href);
91 addToast(t('event.actions.copied'));
92 return true;
93 }
94 };
95
96 if (!event) return <Loading />;
97
98 return (
99 <Layout
100 pageTitle={t('event.title', {title: event.name})}
101 menuTitle={t('event.title', {title: event.name})}
102 displayMenu={false}
103 >
104 <EventBar
105 event={event}
106 onAdd={setIsAddToMyEvent}
107 onSave={onSave}
108 onShare={onShare}
109 />
110 <TravelColumns toggle={toggleVehicleChoice} />
111 <Box className={classes.bottomRight}>
112 <Fab
113 onClick={(user ? toggleVehicleChoice : toggleNewTravel)}
114 aria-label="add-car"
115 color="primary"
116 >
117 {t('travel.creation.title')}
118 </Fab>
119 </Box>
120 <NewTravelDialog open={openNewTravel} toggle={toggleNewTravel} />
121 <VehicleChoiceDialog
122 open={openVehicleChoice}
123 toggle={toggleVehicleChoice}
124 toggleNewTravel={toggleNewTravel}
125 />
126 <AddToMyEventDialog
127 event={event}
128 open={isAddToMyEvent}
129 onClose={() => setIsAddToMyEvent(false)}
130 />
131 <WelcomeDialog />
132 <OnBoardingTour />
133 </Layout>
134 );
135};
136
137export async function getServerSideProps(ctx) {
138 const {uuid} = ctx.query;
139 const apolloClient = initializeApollo();
140 const {data = {}} = await apolloClient.query({
141 query: EventByUuidDocument,
142 variables: {uuid},
143 });
144 const {eventByUUID: event} = data;
145 const {host = ''} = ctx.req.headers;
146
147 return {
148 props: {
149 event,
150 eventUUID: uuid,
151 metas: {
152 title: event?.name || '',
153 url: `https://${host}${ctx.resolvedUrl}`,
154 },
155 },
156 };
157}
158
159const useStyles = makeStyles(theme => ({
160 bottomRight: {
161 position: 'absolute',
162 bottom: theme.spacing(1),
163 right: theme.spacing(6),
164 width: 200,
165 },
166}));
167
168export default EventPage;